<?php

declare(strict_types=1);

namespace base\common\command\admin;

use app\common\tools\PathTools;
use think\App as ThinkApp;
use think\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;

class VersionBase extends Command
{
    public const VERSION = 'v2.0.119';

    public const PRODUCT_VERSION = '';

    public const LAYUI_VERSION = 'v2.10.1';

    public const COMMENT = [
        '版本更新说明：',
        '【新功能】',
        '- 增加地图搜索；增加地图表单字段重置；',
        '【修复】',
        '- 修复没有有效统计数据时仍然显示之前的统计信息的问题',
    ];

    protected const COMMIT_TYPES = [
        'feat' => '新功能',
        'fix' => '修复',
        'docs' => '文档',
        'style' => '样式',
        'refactor' => '重构',
        'perf' => '性能优化',
        'test' => '测试',
        'build' => '构建',
        'ci' => '持续集成',
        'chore' => '其他',
        'revert' => '回退',
    ];

    protected function configure()
    {
        // 指令配置
        $this->setName('admin:version')
            ->addOption('generate-comment', null, Option::VALUE_NONE, '使用git命令生成说明文件')
            ->addOption('generate-release', null, Option::VALUE_NONE, '使用git命令生成发布说明文件')
            ->addOption('release-from-tag', null, Option::VALUE_OPTIONAL, '从指定版本开始生成说明文件')
            ->addOption('push-tag', null, Option::VALUE_NONE, '使用git命令生成tag并推送')
            ->setDescription('查看当前ulthon_admin的版本号');
    }

    protected function execute(Input $input, Output $output)
    {
        // 指令输出
        if (!empty(static::PRODUCT_VERSION)) {
            $output->info('当前版本号为：' . static::PRODUCT_VERSION);
        }
        $output->info('当前ulthon_admin版本号为：' . static::VERSION);
        $output->info('当前Layui版本号为：' . static::LAYUI_VERSION);
        $output->info('当前ThinkPHP版本号为：' . ThinkApp::VERSION);

        $output->writeln('当前的修改说明:');
        $output->writeln('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>');

        foreach (static::COMMENT as  $comment) {
            $output->info($comment);
        }
        $output->writeln('<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<');

        $output->highlight('代码托管地址：https://gitee.com/ulthon/ulthon_admin');
        $output->highlight('开发文档地址：http://doc.ulthon.com/home/read/ulthon_admin/home.html');

        $is_push_tag = $input->hasOption('push-tag');
        if ($is_push_tag) {
            $this->pushTag();
        }

        $is_generate_comment = $input->hasOption('generate-comment');
        if ($is_generate_comment) {
            $this->generateComment();
        }

        $is_generate_release = $input->hasOption('generate-release');
        if ($is_generate_release) {
            $fromTag = $input->getOption('release-from-tag');
            $this->generateRelease($fromTag);
        }
    }

    protected function pushTag()
    {
        $input = $this->input;
        $output = $this->output;

        $output->writeln('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>');

        $version = static::VERSION;
        if (!empty(static::PRODUCT_VERSION)) {
            $version = static::PRODUCT_VERSION;
        }

        // 将提交信息写入临时文件
        $comment = implode("\n", static::COMMENT);
        $output->info('生成标签：' . $version);
        $output->info('标签描述：' . $comment);

        // 使用项目的临时文件路径生成方法
        $tempFile = PathTools::tempBuildPath('git_tag_message_' . uniqid() . '.txt');
        file_put_contents($tempFile, $comment);

        // 使用 -F 参数从文件读取提交信息
        exec("git tag -a $version -F \"$tempFile\"");

        // 删除临时文件
        if (file_exists($tempFile)) {
            unlink($tempFile);
        }
        $output->info('推送到远程仓库');
        exec('git push --tags');
    }

    /**
     * 生成版本更新说明
     * 读取自上次tag到现在所有的提交说明.
     * @return string
     */
    protected function generateComment()
    {
        $this->output->writeln('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>');
        // 获取最新的tag
        $lastTag = shell_exec('git describe --tags --abbrev=0');
        $lastTag = trim($lastTag);

        // 获取从最新tag到现在的所有提交
        $commits = shell_exec("git log {$lastTag}..HEAD --pretty=format:\"%s\"");

        if (empty($commits)) {
            return '暂无更新说明';
        }

        $commits = explode("\n", $commits);

        $groupedCommits = $this->groupCommitsByType($commits, function ($message) {
            return trim($message);
        });

        // 生成更新说明
        $comment = "版本更新说明：\n";

        foreach (static::COMMIT_TYPES as $type => $desc) {
            if (!empty($groupedCommits[$desc])) {
                $comment .= "\n【{$desc}】\n";
                foreach ($groupedCommits[$desc] as $message) {
                    $comment .= "- {$message}\n";
                }
            }
        }

        $this->output->writeln($comment);

        // 生成数组格式文件
        $comment_arr = explode("\n", $comment);
        $comment_arr = array_filter($comment_arr, function ($item) {
            return !empty($item);
        });
        $comment_arr = array_map(function ($item) {
            return "'" . addslashes(trim($item)) . "',";
        }, $comment_arr);

        $comment_arr_code = implode("\n", $comment_arr);
        $tmp_comment_file = PathTools::tempBuildPath('commit_comment.php');
        file_put_contents($tmp_comment_file, "<?php\nreturn [\n" . $comment_arr_code . "\n];");
        $this->output->info('已生成版本更新代码：' . $tmp_comment_file);

        $tmp_comment_markdown_file = PathTools::tempBuildPath('commit_comment.md');
        file_put_contents($tmp_comment_markdown_file, $comment);
        $this->output->info('已生成版本更新Markdown：' . $tmp_comment_markdown_file);
    }

    /**
     * 生成发布说明文件
     * 从指定版本开始生成发布说明.
     * @param string|null $fromTag 起始版本号，如果为空则使用最近的tag
     * @return void
     */
    public function generateRelease($fromTag = null)
    {
        $output = $this->output;

        // 获取所有tags，按时间倒序排列
        $tags = explode("\n", trim(shell_exec('git tag --sort=-creatordate')));

        if (empty($tags)) {
            $output->error('没有找到任何tag');

            return;
        }

        $toTag = $tags[0]; // 最新的tag
        if (empty($fromTag)) {
            if (count($tags) < 2) {
                $output->error('没有足够的tag来生成发布说明');

                return;
            }
            $fromTag = $tags[1]; // 倒数第二个tag
            $output->info('未指定起始版本，使用倒数第二个tag: ' . $fromTag);
        } else {
            if (!in_array($fromTag, $tags)) {
                $output->error('指定的起始版本 ' . $fromTag . ' 不存在');

                return;
            }
            if (version_compare($fromTag, $toTag, '>=')) {
                $output->error('指定的起始版本 ' . $fromTag . ' 不早于最新版本 ' . $toTag);

                return;
            }
        }

        $output->info('从版本 ' . $fromTag . ' 生成发布说明');
        $output->info('到最新tag: ' . $toTag);
        // 获取当前版本
        $currentVersion = static::PRODUCT_VERSION ?: static::VERSION;

        // 获取从指定tag到目标tag的所有提交，包含提交哈希和提交日期
        $commits = shell_exec("git log {$fromTag}..{$toTag} --pretty=format:\"%h|%ad|%s\" --date=short");

        if (empty($commits)) {
            $output->warning('从 ' . $fromTag . ' 到 ' . $toTag . ' 没有任何提交');

            return;
        }

        $commits = explode("\n", $commits);

        $groupedCommits = $this->groupCommitsByType($commits, function ($message, $fullCommit) {
            $parts = explode('|', $fullCommit);
            if (count($parts) >= 3) {
                return [
                    'message' => trim($message),
                    'hash' => $parts[0],
                    'date' => $parts[1],
                ];
            }

            return null;
        });

        // 生成发布说明
        $releaseTitle = "## {$currentVersion} 发布说明\n\n";
        $releaseDate = '发布日期: ' . date('Y-m-d') . "\n\n";
        $releaseContent = "本次发布包含了从 {$fromTag} 到 {$currentVersion} 的所有更新。\n\n";

        foreach (static::COMMIT_TYPES as $type => $desc) {
            if (!empty($groupedCommits[$desc])) {
                $releaseContent .= "### {$desc}\n\n";
                foreach ($groupedCommits[$desc] as $item) {
                    $releaseContent .= "- [{$item['date']}] {$item['message']} (#{$item['hash']})\n";
                }
                $releaseContent .= "\n";
            }
        }

        $release = $releaseTitle . $releaseDate . $releaseContent;

        // 生成发布说明文件
        $releaseFile = PathTools::tempBuildPath("release_{$currentVersion}.md");
        file_put_contents($releaseFile, $release);
        $output->info('已生成发布说明文件: ' . $releaseFile);
    }

    protected function groupCommitsByType($commits, $formatCallback)
    {
        $groupedCommits = [];
        foreach (static::COMMIT_TYPES as $type => $desc) {
            $groupedCommits[$desc] = [];
        }
        $groupedCommits['其他'] = []; // 添加"其他"类别

        foreach ($commits as $commit) {
            $parts = explode('|', $commit);
            $message = $parts[2] ?? $commit;
            $matched = false;
            foreach (static::COMMIT_TYPES as $type => $desc) {
                if (preg_match("/^{$type}:/i", $message)) {
                    $cleanMessage = preg_replace("/^{$type}:/i", '', $message);
                    $groupedCommits[$desc][] = $formatCallback($cleanMessage, $commit);
                    $matched = true;
                    break;
                }
            }

            // 如果没有匹配到任何类型，归类为"其他"
            if (!$matched) {
                $groupedCommits['其他'][] = $formatCallback($message, $commit);
            }
        }

        // 清空空分组
        foreach (array_keys($groupedCommits) as $key) {
            if (empty($groupedCommits[$key])) {
                unset($groupedCommits[$key]);
            }
        }

        return $groupedCommits;
    }
}
